001    /*
002     *  Copyright 2001-2005 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.time;
017    
018    import java.io.Serializable;
019    
020    /**
021     * Identifies a field, such as year or minuteOfHour, in a chronology-neutral way.
022     * <p>
023     * A field type defines the type of the field, such as hourOfDay.
024     * If does not directly enable any calculations, however it does provide a
025     * {@link #getField(Chronology)} method that returns the actual calculation engine
026     * for a particular chronology.
027     * It also provides access to the related {@link DurationFieldType}s.
028     * <p>
029     * Instances of <code>DateTimeFieldType</code> are singletons.
030     * They can be compared using <code>==</code>.
031     * <p>
032     * If required, you can create your own field, for example a quarterOfYear.
033     * You must create a subclass of <code>DateTimeFieldType</code> that defines the field type.
034     * This class returns the actual calculation engine from {@link #getField(Chronology)}.
035     *
036     * @author Stephen Colebourne
037     * @author Brian S O'Neill
038     * @since 1.0
039     */
040    public abstract class DateTimeFieldType implements Serializable {
041    
042        /** Serialization version */
043        private static final long serialVersionUID = -42615285973990L;
044    
045        /** Ordinal values for standard field types. */
046        static final byte
047            ERA = 1,
048            YEAR_OF_ERA = 2,
049            CENTURY_OF_ERA = 3,
050            YEAR_OF_CENTURY = 4,
051            YEAR = 5,
052            DAY_OF_YEAR = 6,
053            MONTH_OF_YEAR = 7,
054            DAY_OF_MONTH = 8,
055            WEEKYEAR_OF_CENTURY = 9,
056            WEEKYEAR = 10,
057            WEEK_OF_WEEKYEAR = 11,
058            DAY_OF_WEEK = 12,
059            HALFDAY_OF_DAY = 13,
060            HOUR_OF_HALFDAY = 14,
061            CLOCKHOUR_OF_HALFDAY = 15,
062            CLOCKHOUR_OF_DAY = 16,
063            HOUR_OF_DAY = 17,
064            MINUTE_OF_DAY = 18,
065            MINUTE_OF_HOUR = 19,
066            SECOND_OF_DAY = 20,
067            SECOND_OF_MINUTE = 21,
068            MILLIS_OF_DAY = 22,
069            MILLIS_OF_SECOND = 23;
070    
071        /** The era field type. */
072        private static final DateTimeFieldType ERA_TYPE = new StandardDateTimeFieldType(
073            "era", ERA, DurationFieldType.eras(), null);
074        /** The yearOfEra field type. */
075        private static final DateTimeFieldType YEAR_OF_ERA_TYPE = new StandardDateTimeFieldType(
076            "yearOfEra", YEAR_OF_ERA, DurationFieldType.years(), DurationFieldType.eras());
077        /** The centuryOfEra field type. */
078        private static final DateTimeFieldType CENTURY_OF_ERA_TYPE = new StandardDateTimeFieldType(
079            "centuryOfEra", CENTURY_OF_ERA, DurationFieldType.centuries(), DurationFieldType.eras());
080        /** The yearOfCentury field type. */
081        private static final DateTimeFieldType YEAR_OF_CENTURY_TYPE = new StandardDateTimeFieldType(
082            "yearOfCentury", YEAR_OF_CENTURY, DurationFieldType.years(), DurationFieldType.centuries());
083        /** The year field type. */
084        private static final DateTimeFieldType YEAR_TYPE = new StandardDateTimeFieldType(
085            "year", YEAR, DurationFieldType.years(), null);
086        /** The dayOfYear field type. */
087        private static final DateTimeFieldType DAY_OF_YEAR_TYPE = new StandardDateTimeFieldType(
088            "dayOfYear", DAY_OF_YEAR, DurationFieldType.days(), DurationFieldType.years());
089        /** The monthOfYear field type. */
090        private static final DateTimeFieldType MONTH_OF_YEAR_TYPE = new StandardDateTimeFieldType(
091            "monthOfYear", MONTH_OF_YEAR, DurationFieldType.months(), DurationFieldType.years());
092        /** The dayOfMonth field type. */
093        private static final DateTimeFieldType DAY_OF_MONTH_TYPE = new StandardDateTimeFieldType(
094            "dayOfMonth", DAY_OF_MONTH, DurationFieldType.days(), DurationFieldType.months());
095        /** The weekyearOfCentury field type. */
096        private static final DateTimeFieldType WEEKYEAR_OF_CENTURY_TYPE = new StandardDateTimeFieldType(
097            "weekyearOfCentury", WEEKYEAR_OF_CENTURY, DurationFieldType.weekyears(), DurationFieldType.centuries());
098        /** The weekyear field type. */
099        private static final DateTimeFieldType WEEKYEAR_TYPE = new StandardDateTimeFieldType(
100            "weekyear", WEEKYEAR, DurationFieldType.weekyears(), null);
101        /** The weekOfWeekyear field type. */
102        private static final DateTimeFieldType WEEK_OF_WEEKYEAR_TYPE = new StandardDateTimeFieldType(
103            "weekOfWeekyear", WEEK_OF_WEEKYEAR, DurationFieldType.weeks(), DurationFieldType.weekyears());
104        /** The dayOfWeek field type. */
105        private static final DateTimeFieldType DAY_OF_WEEK_TYPE = new StandardDateTimeFieldType(
106            "dayOfWeek", DAY_OF_WEEK, DurationFieldType.days(), DurationFieldType.weeks());
107    
108        /** The halfday field type. */
109        private static final DateTimeFieldType HALFDAY_OF_DAY_TYPE = new StandardDateTimeFieldType(
110            "halfdayOfDay", HALFDAY_OF_DAY, DurationFieldType.halfdays(), DurationFieldType.days());
111        /** The hourOfHalfday field type. */
112        private static final DateTimeFieldType HOUR_OF_HALFDAY_TYPE = new StandardDateTimeFieldType(
113            "hourOfHalfday", HOUR_OF_HALFDAY, DurationFieldType.hours(), DurationFieldType.halfdays());
114        /** The clockhourOfHalfday field type. */
115        private static final DateTimeFieldType CLOCKHOUR_OF_HALFDAY_TYPE = new StandardDateTimeFieldType(
116            "clockhourOfHalfday", CLOCKHOUR_OF_HALFDAY, DurationFieldType.hours(), DurationFieldType.halfdays());
117        /** The clockhourOfDay field type. */
118        private static final DateTimeFieldType CLOCKHOUR_OF_DAY_TYPE = new StandardDateTimeFieldType(
119            "clockhourOfDay", CLOCKHOUR_OF_DAY, DurationFieldType.hours(), DurationFieldType.days());
120        /** The hourOfDay field type. */
121        private static final DateTimeFieldType HOUR_OF_DAY_TYPE = new StandardDateTimeFieldType(
122            "hourOfDay", HOUR_OF_DAY, DurationFieldType.hours(), DurationFieldType.days());
123        /** The minuteOfDay field type. */
124        private static final DateTimeFieldType MINUTE_OF_DAY_TYPE = new StandardDateTimeFieldType(
125            "minuteOfDay", MINUTE_OF_DAY, DurationFieldType.minutes(), DurationFieldType.days());
126        /** The minuteOfHour field type. */
127        private static final DateTimeFieldType MINUTE_OF_HOUR_TYPE = new StandardDateTimeFieldType(
128            "minuteOfHour", MINUTE_OF_HOUR, DurationFieldType.minutes(), DurationFieldType.hours());
129        /** The secondOfDay field type. */
130        private static final DateTimeFieldType SECOND_OF_DAY_TYPE = new StandardDateTimeFieldType(
131            "secondOfDay", SECOND_OF_DAY, DurationFieldType.seconds(), DurationFieldType.days());
132        /** The secondOfMinute field type. */
133        private static final DateTimeFieldType SECOND_OF_MINUTE_TYPE = new StandardDateTimeFieldType(
134            "secondOfMinute", SECOND_OF_MINUTE, DurationFieldType.seconds(), DurationFieldType.minutes());
135        /** The millisOfDay field type. */
136        private static final DateTimeFieldType MILLIS_OF_DAY_TYPE = new StandardDateTimeFieldType(
137            "millisOfDay", MILLIS_OF_DAY, DurationFieldType.millis(), DurationFieldType.days());
138        /** The millisOfSecond field type. */
139        private static final DateTimeFieldType MILLIS_OF_SECOND_TYPE = new StandardDateTimeFieldType(
140            "millisOfSecond", MILLIS_OF_SECOND, DurationFieldType.millis(), DurationFieldType.seconds());
141    
142        /** The name of the field. */
143        private final String iName;
144    
145        //-----------------------------------------------------------------------
146        /**
147         * Constructor.
148         * 
149         * @param name  the name to use
150         */
151        protected DateTimeFieldType(String name) {
152            super();
153            iName = name;
154        }
155    
156        //-----------------------------------------------------------------------
157        /**
158         * Get the millis of second field type.
159         * 
160         * @return the DateTimeFieldType constant
161         */
162        public static DateTimeFieldType millisOfSecond() {
163            return MILLIS_OF_SECOND_TYPE;
164        }
165    
166        /**
167         * Get the millis of day field type.
168         * 
169         * @return the DateTimeFieldType constant
170         */
171        public static DateTimeFieldType millisOfDay() {
172            return MILLIS_OF_DAY_TYPE;
173        }
174    
175        /**
176         * Get the second of minute field type.
177         * 
178         * @return the DateTimeFieldType constant
179         */
180        public static DateTimeFieldType secondOfMinute() {
181            return SECOND_OF_MINUTE_TYPE;
182        }
183    
184        /**
185         * Get the second of day field type.
186         * 
187         * @return the DateTimeFieldType constant
188         */
189        public static DateTimeFieldType secondOfDay() {
190            return SECOND_OF_DAY_TYPE;
191        }
192    
193        /**
194         * Get the minute of hour field type.
195         * 
196         * @return the DateTimeFieldType constant
197         */
198        public static DateTimeFieldType minuteOfHour() {
199            return MINUTE_OF_HOUR_TYPE;
200        }
201    
202        /**
203         * Get the minute of day field type.
204         * 
205         * @return the DateTimeFieldType constant
206         */
207        public static DateTimeFieldType minuteOfDay() {
208            return MINUTE_OF_DAY_TYPE;
209        }
210    
211        /**
212         * Get the hour of day (0-23) field type.
213         * 
214         * @return the DateTimeFieldType constant
215         */
216        public static DateTimeFieldType hourOfDay() {
217            return HOUR_OF_DAY_TYPE;
218        }
219    
220        /**
221         * Get the hour of day (offset to 1-24) field type.
222         * 
223         * @return the DateTimeFieldType constant
224         */
225        public static DateTimeFieldType clockhourOfDay() {
226            return CLOCKHOUR_OF_DAY_TYPE;
227        }
228    
229        /**
230         * Get the hour of am/pm (0-11) field type.
231         * 
232         * @return the DateTimeFieldType constant
233         */
234        public static DateTimeFieldType hourOfHalfday() {
235            return HOUR_OF_HALFDAY_TYPE;
236        }
237    
238        /**
239         * Get the hour of am/pm (offset to 1-12) field type.
240         * 
241         * @return the DateTimeFieldType constant
242         */
243        public static DateTimeFieldType clockhourOfHalfday() {
244            return CLOCKHOUR_OF_HALFDAY_TYPE;
245        }
246    
247        /**
248         * Get the AM(0) PM(1) field type.
249         * 
250         * @return the DateTimeFieldType constant
251         */
252        public static DateTimeFieldType halfdayOfDay() {
253            return HALFDAY_OF_DAY_TYPE;
254        }
255    
256        //-----------------------------------------------------------------------
257        /**
258         * Get the day of week field type.
259         * 
260         * @return the DateTimeFieldType constant
261         */
262        public static DateTimeFieldType dayOfWeek() {
263            return DAY_OF_WEEK_TYPE;
264        }
265    
266        /**
267         * Get the day of month field type.
268         * 
269         * @return the DateTimeFieldType constant
270         */
271        public static DateTimeFieldType dayOfMonth() {
272            return DAY_OF_MONTH_TYPE;
273        }
274    
275        /**
276         * Get the day of year field type.
277         * 
278         * @return the DateTimeFieldType constant
279         */
280        public static DateTimeFieldType dayOfYear() {
281            return DAY_OF_YEAR_TYPE;
282        }
283    
284        /**
285         * Get the week of a week based year field type.
286         * 
287         * @return the DateTimeFieldType constant
288         */
289        public static DateTimeFieldType weekOfWeekyear() {
290            return WEEK_OF_WEEKYEAR_TYPE;
291        }
292    
293        /**
294         * Get the year of a week based year field type.
295         * 
296         * @return the DateTimeFieldType constant
297         */
298        public static DateTimeFieldType weekyear() {
299            return WEEKYEAR_TYPE;
300        }
301    
302        /**
303         * Get the year of a week based year within a century field type.
304         * 
305         * @return the DateTimeFieldType constant
306         */
307        public static DateTimeFieldType weekyearOfCentury() {
308            return WEEKYEAR_OF_CENTURY_TYPE;
309        }
310    
311        /**
312         * Get the month of year field type.
313         * 
314         * @return the DateTimeFieldType constant
315         */
316        public static DateTimeFieldType monthOfYear() {
317            return MONTH_OF_YEAR_TYPE;
318        }
319    
320        /**
321         * Get the year field type.
322         * 
323         * @return the DateTimeFieldType constant
324         */
325        public static DateTimeFieldType year() {
326            return YEAR_TYPE;
327        }
328    
329        /**
330         * Get the year of era field type.
331         * 
332         * @return the DateTimeFieldType constant
333         */
334        public static DateTimeFieldType yearOfEra() {
335            return YEAR_OF_ERA_TYPE;
336        }
337    
338        /**
339         * Get the year of century field type.
340         * 
341         * @return the DateTimeFieldType constant
342         */
343        public static DateTimeFieldType yearOfCentury() {
344            return YEAR_OF_CENTURY_TYPE;
345        }
346    
347        /**
348         * Get the century of era field type.
349         * 
350         * @return the DateTimeFieldType constant
351         */
352        public static DateTimeFieldType centuryOfEra() {
353            return CENTURY_OF_ERA_TYPE;
354        }
355    
356        /**
357         * Get the era field type.
358         * 
359         * @return the DateTimeFieldType constant
360         */
361        public static DateTimeFieldType era() {
362            return ERA_TYPE;
363        }
364    
365        //-----------------------------------------------------------------------
366        /**
367         * Get the name of the field.
368         * <p>
369         * By convention, names follow a pattern of "dddOfRrr", where "ddd" represents
370         * the (singular) duration unit field name and "Rrr" represents the (singular)
371         * duration range field name. If the range field is not applicable, then
372         * the name of the field is simply the (singular) duration field name.
373         * 
374         * @return field name
375         */
376        public String getName() {
377            return iName;
378        }
379    
380        /**
381         * Get the duration unit of the field.
382         * 
383         * @return duration unit of the field, never null
384         */
385        public abstract DurationFieldType getDurationType();
386    
387        /**
388         * Get the duration range of the field.
389         * 
390         * @return duration range of the field, null if unbounded
391         */
392        public abstract DurationFieldType getRangeDurationType();
393    
394        /**
395         * Gets a suitable field for this type from the given Chronology.
396         *
397         * @param chronology  the chronology to use, null means ISOChronology in default zone
398         * @return a suitable field
399         */
400        public abstract DateTimeField getField(Chronology chronology);
401    
402        /**
403         * Checks whether this field supported in the given Chronology.
404         *
405         * @param chronology  the chronology to use, null means ISOChronology in default zone
406         * @return true if supported
407         */
408        public boolean isSupported(Chronology chronology) {
409            return getField(chronology).isSupported();
410        }
411    
412        /**
413         * Get a suitable debug string.
414         * 
415         * @return debug string
416         */
417        public String toString() {
418            return getName();
419        }
420    
421        private static class StandardDateTimeFieldType extends DateTimeFieldType {
422            /** Serialization version */
423            private static final long serialVersionUID = -9937958251642L;
424    
425            /** The ordinal of the standard field type, for switch statements */
426            private final byte iOrdinal;
427    
428            /** The unit duration of the field. */
429            private final transient DurationFieldType iUnitType;
430            /** The range duration of the field. */
431            private final transient DurationFieldType iRangeType;
432    
433            /**
434             * Constructor.
435             * 
436             * @param name  the name to use
437             * @param ordinal  the byte value for the oridinal index
438             * @param unitType  the unit duration type
439             * @param rangeType  the range duration type
440             */
441            StandardDateTimeFieldType(String name, byte ordinal,
442                                      DurationFieldType unitType, DurationFieldType rangeType) {
443                super(name);
444                iOrdinal = ordinal;
445                iUnitType = unitType;
446                iRangeType = rangeType;
447            }
448    
449            /** @inheritdoc */
450            public DurationFieldType getDurationType() {
451                return iUnitType;
452            }
453    
454            /** @inheritdoc */
455            public DurationFieldType getRangeDurationType() {
456                return iRangeType;
457            }
458    
459            /** @inheritdoc */
460            public DateTimeField getField(Chronology chronology) {
461                chronology = DateTimeUtils.getChronology(chronology);
462    
463                switch (iOrdinal) {
464                    case ERA:
465                        return chronology.era();
466                    case YEAR_OF_ERA:
467                        return chronology.yearOfEra();
468                    case CENTURY_OF_ERA:
469                        return chronology.centuryOfEra();
470                    case YEAR_OF_CENTURY:
471                        return chronology.yearOfCentury();
472                    case YEAR:
473                        return chronology.year();
474                    case DAY_OF_YEAR:
475                        return chronology.dayOfYear();
476                    case MONTH_OF_YEAR:
477                        return chronology.monthOfYear();
478                    case DAY_OF_MONTH:
479                        return chronology.dayOfMonth();
480                    case WEEKYEAR_OF_CENTURY:
481                        return chronology.weekyearOfCentury();
482                    case WEEKYEAR:
483                        return chronology.weekyear();
484                    case WEEK_OF_WEEKYEAR:
485                        return chronology.weekOfWeekyear();
486                    case DAY_OF_WEEK:
487                        return chronology.dayOfWeek();
488                    case HALFDAY_OF_DAY:
489                        return chronology.halfdayOfDay();
490                    case HOUR_OF_HALFDAY:
491                        return chronology.hourOfHalfday();
492                    case CLOCKHOUR_OF_HALFDAY:
493                        return chronology.clockhourOfHalfday();
494                    case CLOCKHOUR_OF_DAY:
495                        return chronology.clockhourOfDay();
496                    case HOUR_OF_DAY:
497                        return chronology.hourOfDay();
498                    case MINUTE_OF_DAY:
499                        return chronology.minuteOfDay();
500                    case MINUTE_OF_HOUR:
501                        return chronology.minuteOfHour();
502                    case SECOND_OF_DAY:
503                        return chronology.secondOfDay();
504                    case SECOND_OF_MINUTE:
505                        return chronology.secondOfMinute();
506                    case MILLIS_OF_DAY:
507                        return chronology.millisOfDay();
508                    case MILLIS_OF_SECOND:
509                        return chronology.millisOfSecond();
510                    default:
511                        // Shouldn't happen.
512                        throw new InternalError();
513                }
514            }
515    
516            /**
517             * Ensure a singleton is returned.
518             * 
519             * @return the singleton type
520             */
521            private Object readResolve() {
522                switch (iOrdinal) {
523                    case ERA:
524                        return ERA_TYPE;
525                    case YEAR_OF_ERA:
526                        return YEAR_OF_ERA_TYPE;
527                    case CENTURY_OF_ERA:
528                        return CENTURY_OF_ERA_TYPE;
529                    case YEAR_OF_CENTURY:
530                        return YEAR_OF_CENTURY_TYPE;
531                    case YEAR:
532                        return YEAR_TYPE;
533                    case DAY_OF_YEAR:
534                        return DAY_OF_YEAR_TYPE;
535                    case MONTH_OF_YEAR:
536                        return MONTH_OF_YEAR_TYPE;
537                    case DAY_OF_MONTH:
538                        return DAY_OF_MONTH_TYPE;
539                    case WEEKYEAR_OF_CENTURY:
540                        return WEEKYEAR_OF_CENTURY_TYPE;
541                    case WEEKYEAR:
542                        return WEEKYEAR_TYPE;
543                    case WEEK_OF_WEEKYEAR:
544                        return WEEK_OF_WEEKYEAR_TYPE;
545                    case DAY_OF_WEEK:
546                        return DAY_OF_WEEK_TYPE;
547                    case HALFDAY_OF_DAY:
548                        return HALFDAY_OF_DAY_TYPE;
549                    case HOUR_OF_HALFDAY:
550                        return HOUR_OF_HALFDAY_TYPE;
551                    case CLOCKHOUR_OF_HALFDAY:
552                        return CLOCKHOUR_OF_HALFDAY_TYPE;
553                    case CLOCKHOUR_OF_DAY:
554                        return CLOCKHOUR_OF_DAY_TYPE;
555                    case HOUR_OF_DAY:
556                        return HOUR_OF_DAY_TYPE;
557                    case MINUTE_OF_DAY:
558                        return MINUTE_OF_DAY_TYPE;
559                    case MINUTE_OF_HOUR:
560                        return MINUTE_OF_HOUR_TYPE;
561                    case SECOND_OF_DAY:
562                        return SECOND_OF_DAY_TYPE;
563                    case SECOND_OF_MINUTE:
564                        return SECOND_OF_MINUTE_TYPE;
565                    case MILLIS_OF_DAY:
566                        return MILLIS_OF_DAY_TYPE;
567                    case MILLIS_OF_SECOND:
568                        return MILLIS_OF_SECOND_TYPE;
569                    default:
570                        // Shouldn't happen.
571                        return this;
572                }
573            }
574        }
575    
576    }